#include <QGraphicsView>
#include <QFileDialog>
#include <QInputDialog>
#include <QRect>
#include <QPen>

#include <iostream>
#include "base/Point.h"
#include "io/FileReader.h"
#include "io/TxtFileReader.h"
#include "io/TxtFileWriter.h"
#include "io/JsonFileReader.h"
#include "io/JsonFileWriter.h"
#include "algo/DacAlgorithm.h"
#include "algo/RandomAlgorithm.h"
#include "ui/AboutDialog.h"
#include "ui_aboutdialog.h"
#include "ui/MainWindow.h"
#include "ui_mainwindow.h"

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->statusBar()->hide();
    setFixedSize(200+GraphicScene::MAX_BOUNDS+4*GraphicScene::MARGIN,
                 GraphicScene::MAX_BOUNDS+4*GraphicScene::MARGIN);

    ui->graphicsView->setGeometry(GraphicScene::MARGIN,
                                  GraphicScene::MARGIN,
                                  GraphicScene::MAX_BOUNDS+2*GraphicScene::MARGIN,
                                  GraphicScene::MAX_BOUNDS+2*GraphicScene::MARGIN);
    ui->graphicsView->setScene(&scene);
    connect(ui->actionOuvrir, SIGNAL(triggered()), this, SLOT(open_file()));
    connect(ui->action_propos, SIGNAL(triggered()), this, SLOT(show_about_window()));
    connect(ui->actionQuitter, SIGNAL(triggered()), this, SLOT(close()));
    connect(ui->actionSauvegarder_les_points, SIGNAL(triggered()), this, SLOT(save()));
    connect(ui->displayHull, SIGNAL(toggled(bool)), this, SLOT(displayHull(bool)));
    connect(ui->algoChoice, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAlgo(int)));
    connect(ui->optiLosange, SIGNAL(toggled(bool)), this, SLOT(changeOpti(bool)));
    connect(ui->generateButton, SIGNAL(clicked()), this, SLOT(random_points()));
    connect(ui->nbPoints, SIGNAL(valueChanged(int)), this, SLOT(random_points()));
    changeAlgo(0);
    changeOpti(false);
    this->random_points();
    this->scene.show_hull(false);
}

void MainWindow::changeOpti(bool state) {
    this->scene.setOptimization(state);
    this->scene.show_hull(true);
}

void MainWindow::changeAlgo(int index) {
    if (index == 0) {
        this->scene.setAlgo(new DaCAlgorithm());
    } else if (index == 1) {
        this->scene.setAlgo(new RandomAlgorithm());
    }
    this->scene.show_hull(true);
}

void MainWindow::displayHull(bool state) {
    ui->optiLosange->setEnabled(state);
    ui->algoChoice->setEnabled(state);
    this->scene.show_hull(state);
}

void MainWindow::save()
{
    QString filter;
    QString file_name = QFileDialog::getSaveFileName(this, QString::fromAscii("Ouvrir un fichier de points"),
                                                     QString(),
                                                     QString::fromAscii("Fichier texte (*.txt);;Fichier JSON (*.json)"),
                                                     &filter);
    FileWriter* writer;
    if (filter == "Fichier texte (*.txt)") {
        if (!file_name.endsWith(".txt", Qt::CaseInsensitive)) {
            file_name += ".txt";
        }
        writer = new TxtFileWriter(qstrdup(qPrintable(file_name)));
    } else if (filter == "Fichier JSON (*.json)") {
        if (!file_name.endsWith(".json", Qt::CaseInsensitive)) {
            file_name += ".json";
        }
        writer = new JsonFileWriter(qstrdup(qPrintable(file_name)));
    } else {
        return;
    }
    writer->write(this->scene.getPoints(), this->scene.getHull());
}

void MainWindow::open_file() {
    this->scene.clear();
    QString file_name = QFileDialog::getOpenFileName(this, QString::fromAscii("Ouvrir un fichier de points"),
                                                     QString(),
                                                     QString::fromAscii("Tous les fichiers (*.txt *.json);;Fichier texte (*.txt);;Fichier JSON (*.json)"));
    FileReader* reader;
    if (file_name.toLower().endsWith(".txt")) {
        reader = new TxtFileReader(qstrdup(qPrintable(file_name)));
    } else if (file_name.toLower().endsWith(".json")) {
        reader = new JsonFileReader(qstrdup(qPrintable(file_name)));
    } else {
        return;
    }
    _points = reader->read_points();
    this->scene.plotPoints(_points);
}

void MainWindow::show_about_window() {
    AboutDialog about_dialog(this);
    about_dialog.exec();
}

void MainWindow::random_points() {
    this->scene.clear();
    _points = point_list::get_random_points(ui->nbPoints->value(),
                                            0,
                                            GraphicScene::MAX_BOUNDS);
    this->scene.plotPoints(_points);
    this->scene.plotHull();
}

MainWindow::~MainWindow()
{
    delete ui;
}
